=begin pod

=TITLE class Parameter

=SUBTITLE Element of a Signature

    class Parameter { }

Represents a parameter, for purpose of introspection.

The usual way to obtain a Parameter object is to create a signature,
and call C<.params> on it to obtain a list of the Parameters.

    my $sig   = :(Str $x);
    my $param = $sig.params[0];
    say $param.type;              # OUTPUT: «Str()␤»

See L<Signature> for more information, and also for an explanation
on what most of the concepts related to parameters mean.

=head1 Methods

=head2 method name

Returns the variable name, which includes all sigils and twigils.
This name is used internally when applied to code, or in a declaration
determines the name declared.  This name is not necessarily
usable by a caller – if it is, it will also appear as an
L<alias|#method named_names>.  Often, the name will chosen descriptively
as a form of self-documentation.

If the parameter is anonymous, C<Nil> will be returned.

=head2 method sigil

Defined as:

    method sigil(Parameter:D: --> Str:D)

Returns a string containing the parameter's sigil, for a looser
definition of "sigil" than what is considered part of
the variable's C<name|method name>.  Still returns a sigil even
if the parameter is anonymous.

This "sigil" is actually an introspection used to help determine
the normal binding style of a parameter, if it has not been altered
through a L<trait|/type/Signature#Parameter_Traits_and_Modifiers>.

=begin table
   Will bind to           Default behavior
 =  ======================  ================================================================
 C<$>  Scalar                  Generate new Scalar, use instead of Scalar in argument, if any
 C<@>  Positional              Bind directly to the argument
 C<@>  PositionalBindFailover  If binding failed, call argument's .cache method, bind to result
 C<%>  Associative             Bind directly to the argument
 C<&>  Callable                Bind directly to the argument
 C<|>  (anything)              Bind to all remaining arguments, make new Capture if needed
 C<\>  (anything)              Bind directly to the argument, keep existing Scalar, if any
=end table

=head2 method type

Returns the L<nominal type constraint|/type/Signature#Type_Constraints> of
the parameter.

=head2 method constraints

Returns L<additional constraints|/type/Signature#Type_Constraints> on the
parameter (usually as an C<all>-Junction).

=head2 method named

Defined as:

    method named(Parameter:D: --> Bool:D)

Returns C<True> if it's a L<named parameter|/type/Signature#Positional_vs._Named>.

    my Signature $sig = :(Str $x, Bool :$is-named);
    say $sig.params[0].named;                          # OUTPUT: «False␤»
    say $sig.params[1].named;                          # OUTPUT: «True␤»

=head2 method named_names

Defined as:

    method named_names(Parameter:D: --> List:D)

Returns the list of externally usable names/aliases for a
L<named parameter|/type/Signature#Positional_vs._Named>.

=head2 method positional

Defined as:

    method positional(Parameter:D: --> Bool:D)

Returns C<True> if the parameter is
L<positional|/type/Signature#Positional_vs._Named>.

    my Signature $sig = :(Str $x, Bool :$is-named);
    say $sig.params[0].positional;                     # OUTPUT: «True␤»
    say $sig.params[1].positional;                     # OUTPUT: «False␤»

=head2 method slurpy

Defined as:

    method slurpy(Parameter:D: --> Bool:D)

Returns C<True> for
L<slurpy parameters|/type/Signature#Slurpy_(A.K.A._Variadic)_Parameters>.

=head2 method twigil

Defined as:

    method twigil(Parameter:D: --> Str:D)

Returns a string containing the twigil part of the parameter's name.

=head2 method optional

Defined as:

    method optional(Parameter:D: --> Bool:D)

Returns C<True> for
L<optional parameters|/type/Signature#Optional_and_Mandatory_Parameters>.

=head2 method raw

Defined as:

    method raw(Parameter:D: --> Bool:D)

Returns C<True> for raw parameters.

    sub f($a, $b is raw, \c) {
        my $sig = &?ROUTINE.signature;
        for ^$sig.params.elems {
            say $sig.params[$_].raw;
        }
    }
    f(17, "4711", 42); OUTPUT: «False␤True␤True␤»

Raw parameters bind either a variable or a value passed to it, with
no decontainerization taking place.  That means that if a variable was passed
to it, you can assign to the parameter. This is different from
L<rw|#method_rw>-parameter which can only bind to variables, never to values.

This is the normal behavior for parameters declared with a
L<sigil|#method sigil> of C<'\'>, which is not really a sigil insofar
as it is only used on the parameter.

    sub f(\x) {
        x = 5;
    }
    f(my $x);   # works
    f(42);      # dies
    CATCH { default { put .^name, ': ', .Str } };
    # OUTPUT: «X::Assignment::RO: Cannot modify an immutable Int␤»

Other parameters may become raw through use of the 'C<is raw>'
L<trait|/type/Signature#Parameter_Traits_and_Modifiers>.  These still use
their sigil in code.

    sub f($x is raw) {
        $x = 5;
    }

=head2 method capture

Defined as:

    method capture(Parameter:D: --> Bool:D)

Returns C<True> for parameters that capture the rest of the argument list into
a single L<Capture|/type/Capture> object.

    sub how_many_extra_positionals($!, |capture) { capture.elems.say }
    how_many_extra_positionals(0, 1, 2, 3);                        # RESULT: «3»
    say &how_many_extra_positionals.signature.params[1].capture;   # OUTPUT: «True␤»

Like raw parameters, Capture parameters do not force any context on the
values bound to them, which is why their sigils are only used in
declarations.

=head2 method rw

Defined as:

    method rw(Parameter:D: --> Bool:D)

Returns C<True> for L<C<is rw>|/type/Signature#Parameter_Traits_and_Modifiers>
parameters.

    my Signature $sig = :(Str $x is rw, Bool :$is-named);
    say $sig.params[0].rw;                             # OUTPUT: «True␤»
    say $sig.params[1].rw;                             # OUTPUT: «False␤»

=head2 method copy

Defined as:

    method copy(Parameter:D: --> Bool:D)

Returns C<True> for L<C<is copy>|/type/Signature#Parameter_Traits_and_Modifiers>
parameters.

    my Signature $sig = :(Str $x, Bool :$is-named is copy);
    say $sig.params[0].copy;                           # OUTPUT: «False␤»
    say $sig.params[1].copy;                           # OUTPUT: «True␤»

=head2 method readonly

Defined as:

    method readonly(Parameter:D: --> Bool:D)

Returns C<True> for read-only parameters (the default).

    my Signature $sig = :(Str $x is rw, Bool :$is-named);
    say $sig.params[0].readonly;                       # OUTPUT: «False␤»
    say $sig.params[1].readonly;                       # OUTPUT: «True␤»

=head2 method invocant

Defined as:

    method invocant(Parameter:D: --> Bool:D)

Returns C<True> if the parameter is the
L<invocant parameter|/type/Signature#Parameter_Separators>.

=head2 method default

Returns a closure that upon invocation returns the
L<default value|/type/Signature#Optional_and_Mandatory_Parameters> for
this parameter, or C<Any> if no default was provided.

=head2 method type_captures

Defined as:

    method type_captures(Parameter:D: --> List:D)

Returns a list of variable names of type captures associated with this
parameter.  Type captures define a type name within the attached code,
which is an alias to the type gleaned from the argument during a call.

    sub a(::T ::U $x) { T.say }
    a(8);                                       # OUTPUT: «(Int)␤»
    say &a.signature.params[0].type_captures;   # OUTPUT: «(T U)␤»
    sub b($x) { $x.^name.say }
    a(8);                                       # OUTPUT: «Int␤»

The type used may change from call to call.  Once they are defined,
type captures can be used wherever you would use a type, even later
in same the signature:

=for code
sub c(::T $x, T $y, $z) { my T $zz = $z };
c(4, 5, 6);          # OK
c(4, 5, "six");      # Fails when assigning to $zz, wants Int not Str
c("four", 5, "six"); # Fails when binding $y, wants Str, not Int

Type captures may be used at the same time as
L<type constraints|/type/Signature#Type_Constraints>.

=for code
sub d(::T Numeric $x, T $y) {};
d(4, 5);            # OK
d(4e0, 5e0);        # OK
d(4e0, 5);          # Fails when binding $y
d("four", "five");  # Fails when binding $x

=head2 method sub_signature

If the parameter has a
L<sub-signature|/type/Signature#Destructuring_Parameters>,
returns a C<Signature> object for it.  Otherwise returns C<Any>.

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
